/*
 * by cansik / Florian
 * Datum: 29.04.2009
 * Zeit: 10:55
 */
using System;
using System.Collections;
using System.IO;
using System.Reflection;

namespace sEmit.Core
{
	internal class PluginServices
	{
		
		public struct AvailablePlugin
		{
			public string AssemblyPath;
			public string ClassName;
		}
		
		public static AvailablePlugin[] FindPlugins(string strPath, string strInterface)
		{
			ArrayList Plugins = new ArrayList();
			string[] strDLLs = null;
			int intIndex = 0;
			Assembly objDLL = default(Assembly);
			
			//Go through all DLLs in the directory, attempting to load them
			strDLLs = Directory.GetFileSystemEntries(strPath, "*.dll");
			for (intIndex = 0; intIndex <= strDLLs.Length - 1; intIndex++) {
				try {
					objDLL = Assembly.LoadFrom(strDLLs[intIndex]);
					ExamineAssembly(objDLL, strInterface, Plugins);
				}
				catch (Exception) {
				}
				//Error loading DLL, we don't need to do anything special
			}
			
			//Return all plugins found
			AvailablePlugin[] Results = new AvailablePlugin[Plugins.Count];
			
			if (Plugins.Count != 0) {
				Plugins.CopyTo(Results);
				return Results;
			}
			else {
				return null;
			}
		}
		
		private static void ExamineAssembly(Assembly objDLL, string strInterface, ArrayList Plugins)
		{
			Type objInterface = default(Type);
			AvailablePlugin Plugin = default(AvailablePlugin);
			
			//Loop through each type in the DLL
			foreach (var typ in objDLL.GetTypes()) {
				//Only look at public types
				if (typ.IsPublic == true) {
					//Ignore abstract classes
					if (!((typ.Attributes & TypeAttributes.Abstract) == TypeAttributes.Abstract)) {
						
						//See if this type implements our interface
						objInterface = typ.GetInterface(strInterface, true);
						
						if ((objInterface != null)) {
							//It does
							Plugin = new AvailablePlugin();
							Plugin.AssemblyPath = objDLL.Location;
							Plugin.ClassName = typ.FullName;
							Plugins.Add(Plugin);
							
						}
					}
				}
			}
		}
		
		public static object CreateInstance(AvailablePlugin Plugin)
		{
			Assembly objDLL = default(Assembly);
			object objPlugin = null;
			
			try {
				//Load dll
				objDLL = Assembly.LoadFrom(Plugin.AssemblyPath);
				
				//Create and return class instance
				objPlugin = objDLL.CreateInstance(Plugin.ClassName);
			}
			catch (Exception) {
				return null;
			}
			
			return objPlugin;
		}
		
	}
}